var Match = require("js/match").Match;
var Map = require("js/map").Map;
var gamejs = require("gamejs");
var SoundManager = require("js/soundManager").SoundManager;
var utils = require("js/utils");
var missions = require("js/missions");

var testMatch;

qModule("js/match", {
	setup: function() {
		testMatch = new Match();
	}
});


test("Match(health, credit)", function(){
	// Test with default arguments
	ok(testMatch instanceof Match,
		"Test #1 with arguments: (default, default)"
	);
	equal(testMatch.getHealth(), 50,
		"Test with arguments: (default, default): health is correct"
	);
	equal(testMatch.getCredit(), 0,
		"Test #3 with arguments: (default, default): credit is correct"
	);
	equal(testMatch.getScore(), 0,
		"Test #4 with arguments: (default, default): score is correct"
	);
/*	// Test that exception are raised if created with wrong arguments
	throws(
		function() { var errorMatch = new Match(0, 100); },
		TypeError,
		"Test with argument: (0, Number > 0): exception correctly throwed"
	);
	throws(
		function() { var errorMatch = new Match(-1, 100); },
		TypeError,
		"Test with argument: (Number < 0, Number > 0): " +
		"exception correctly throwed"
	);
	throws(
		function() { var errorMatch = new Match(100, -1); },
		TypeError,
		"Test with argument: (Number > 0, Number < 0): " +
		"exception correctly throwed"
	);
	throws(
		function() { var errorMatch = new Match(-1, -1); },
		TypeError,
		"Test with argument: (Number < 0, Number < 0): " +
		"exception correctly throwed"
	);
	throws(
		function() { var errorMatch = new Match(NaN, NaN); },
		TypeError,
		"Test with argument: (NaN, NaN): exception correctly throwed"
	);*/
});

test("Match.getMap()", function(){
	// Match without a Map
	testMatch = new Match();
	throws(
		function(){
			testMatch.getMap();
		}, ReferenceError, "Test #1 on a Match without a map assigned"
	);
	// Normal map
	testMap = new Map(testMatch, 10, 10);
	testMatch.setMap(testMap);
	strictEqual(testMatch.getMap(), testMap,
		"Test #2 on a Match having a Map"
	);
});

test("Match.setMap(map)", function(){
	var testMap = new Map(testMatch, 10, 10);
	// Normal map
	testMatch.setMap(testMap);
	strictEqual(testMatch.getMap(), testMap, "Test #1 with argument: (Map)");
	// Null argument
	throws(
		function(){
			testMatch.setMap(null);
		}, TypeError, " Test #2 with null argument"	
	);
});

test("Match.getHealth()", function(){
	var health = 300;
	var healthMatch = new Match();
	healthMatch.health = health;
	// Normal case
	equal(healthMatch.getHealth(), health, "Test with a regular Match object");
});

test("Match.decreaseHealth(hitpoint)", function() {
	var health = testMatch.getHealth();
	// Test with undefined argument
	var returnedHealth = testMatch.decreaseHealth();
	health = health - 1;
	equal(testMatch.getHealth(), health,
		"Test with argument: (undefined)"
	);
	equal(returnedHealth, health,
		"Test with argument: (undefined): returned health is correct"
	);
	// Test with a Number > 0
	var hit = 10;
	health = health - hit;
	returnedHealth = testMatch.decreaseHealth(hit);
	equal(testMatch.getHealth(), health,
		"Test with argument: (Number > 0)"
	);
	equal(returnedHealth, health,
		"Test with argument: (Number > 0): returned health is correct"
	);
	// Test with 0
	health = testMatch.getHealth();
	returnedHealth = testMatch.decreaseHealth(0);
	equal(testMatch.getHealth(), health,
		"Test with argument: (0)"
	);
	equal(returnedHealth, health,
		"Test with argument: (0): returned health is correct"
	);
	// Test with Number < 0
	hit = -10;
	throws(
		function(){
		testMatch.decreaseHealth(hit);
		}, RangeError, "Test with argument: (Number < 0)"
	);
	equal(returnedHealth, health,
		"Test with argument: (Number < 0): returned health is correct"
	);
	// Test with a Numeric argument greater than current health
	hit = testMatch.getHealth() + 10;
	returnedHealth = testMatch.decreaseHealth(hit);
	equal(testMatch.getHealth(), 0,
		"Test with argument: (Number > Match.health)"
	);
	equal(returnedHealth, 0,
		"Test with argument: (Number > Match.health): " +
		"returned health is correct"
	);
	// Test with NaN
	throws(
		function(){
			testMatch.decreaseHealth(Number.NaN);
		}, TypeError, "Test with NaN"	
	);
	// Test with a string number
	throws(
		function(){
			testMatch.decreaseHealth("12");
		}, TypeError, "Test with a string"	
	);
});

test("Match.getCredit()", function(){
	var credit = 300;
	var creditMatch = new Match();
	creditMatch.credit = credit;
	// Normal case
	equal(creditMatch.getCredit(), credit, "Test with a regular Match object");
});

test("Match.changeCredit(amount)", function() {
	var credit = testMatch.getCredit();
	// Test with undefined argument
	throws(
		function(){
		testMatch.changeCredit();
	}, TypeError, "Test with undefined argument"
	);
	// Test with a Number > 0
	var increment = 10;
	credit = credit + increment;
	returnedCredit = testMatch.changeCredit(increment);
	equal(testMatch.getCredit(), credit,
		"Test with argument: (Number > 0)"
	);
	equal(returnedCredit, credit,
		"Test with argument: (Number > 0): returned credit is correct"
	);
	// Test with 0
	credit = testMatch.getCredit();
	returnedCredit = testMatch.changeCredit(0);
	equal(testMatch.getCredit(), credit,
		"Test with argument: (0)"
	);
	equal(returnedCredit, credit,
		"Test with argument: (0): returned credit is correct"
	);
	// Test with Number < 0
	var decrement = -10;
	credit = credit + decrement;
	returnedCredit = testMatch.changeCredit(decrement);
	equal(testMatch.getCredit(), credit,
		"Test with argument: (Number < 0)"
	);
	equal(returnedCredit, credit,
		"Test with argument: (Number < 0): returned credit is correct"
	);
	// Test a decrement bigger than available credits
	var available = testMatch.getCredit();
	decrement = - (available + 10);
	throws(
		function() { testMatch.changeCredit(decrement); },
		RangeError,
		"Test with argument: (Number < 0 and |Number| > Match.credit)"
	);
	// Test with NaN
	throws(
		function(){
			testMatch.changeCredit(Number.NaN);
		}, TypeError, "Test with NaN"	
	);
	// Test with string number
	throws(
		function(){
			testMatch.changeCredit("10");
		}, TypeError, "Test with string number"	
	);
});

test("Match.getScore()", function() {
	// A new match has score = 0
	equal(testMatch.getScore(), 0, "Test with a regular Match object");
});

test("Match.changeScore(amount)", function() {
	var score = testMatch.getScore();
	// Test with undefined argument
	throws(
		function(){
			testMatch.changeScore();
		}, TypeError, "Test with undefined parameter"	
	);
	// Test with a Number > 0
	var increment = 10;
	score = score + increment;
	returnedScore = testMatch.changeScore(increment);
	equal(testMatch.getScore(), score,
		"Test with argument: (Number > 0)"
	);
	equal(returnedScore, score,
		"Test with argument: (Number > 0): returned score is correct"
	);
	// Test with 0
	score = testMatch.getScore();
	returnedScore = testMatch.changeScore(0);
	equal(testMatch.getScore(), score,
		"Test with argument: (0)"
	);
	equal(returnedScore, score,
		"Test with argument: (0): returned score is correct"
	);
	// Test with Number < 0
	var decrement = -10;
	score = score + decrement;
	returnedScore = testMatch.changeScore(decrement);
	equal(testMatch.getScore(), score,
		"Test with argument: (Number < 0)"
	);
	equal(returnedScore, score,
		"Test with argument: (Number < 0): returned score is correct"
	);
	// Test a decrement bigger than available score
	var available = testMatch.getScore();
	decrement = - (available + 10);
	throws(
		function() { testMatch.changeScore(decrement); },
		RangeError,
		"Test with argument: (Number < 0 and |Number| > Match.score)"
	);
	// Test with string number
	throws(
		function(){
			testMatch.changeScore("10");
		}, TypeError, "Test with string input"	
	);
	// Test with NaN
	throws(
		function(){
			testMatch.changeScore(Number.NaN);
		}, TypeError, "Test with NaN"
	);
});

test("Match.getLevel()", function(){
	testMatch = new Match();
	testMatch.setMap(new Map(testMatch, 100, 100));
	// Normal case
	strictEqual(testMatch.getLevel(), 0," Test #1 check for default value");
	testMatch.start();
	strictEqual(testMatch.getLevel(), 1," Test #2 check after start() call");
});

test("Match.getSoundManager()", function(){
	var sound = new SoundManager();
	testMatch = new Match(sound);
	// Normal case
	strictEqual(testMatch.getSoundManager(), sound, "Test #1 ok with a default parameter");
});

test("Match.isInGame()", function(){
	testMatch = new Match();
	// Normal case
	ok( ! testMatch.isInGame(), "Test #1 ok when it is created a new Match");
	testMatch.setMap(new Map(testMatch, 100, 100));
	testMatch.start();
	ok(testMatch.isInGame(), "Test #2 ok after the start() call");
	var health = testMatch.getHealth();
	testMatch.decreaseHealth(health + 1);
	// Test for lose game
	ok(! testMatch.isInGame(), " Test #3 ok when health is < 0");
});

test("Match.hasCredit()", function(){
	testMatch = new Match();
	// Normal case
	ok(testMatch.hasCredit(0), "Test a normal situation");
	// Test with MAX_VALUE
	ok(! testMatch.hasCredit(Number.MAX_VALUE), "Test with MAX_VALUE");
	// Test with negative number
	throws(
		function(){
			testMatch.hasCredit(-10);
		}, RangeError, "Test with number <0"	
	);
	// Test with string number
	throws(
		function(){
			testMatch.hasCredit("10");
		}, TypeError, "Test with a string input"	
	);
	// Test with NaN
	throws(
		function(){
			testMatch.hasCredit(Number.NaN);
		}, TypeError, "Test with NaN"	
	);
});

test("Match.getMission()", function(){
	testMatch = new Match();
	testMatch.setMap(new Map(testMatch, 100, 100));
	// Normal case
	strictEqual(testMatch.getMission(), 0," Test #1 check for default value");
	testMatch.start();
	strictEqual(testMatch.getMission(), 1," Test #2 check after start() call");
});

test("Match.isLastLevel()", function(){
	testMatch = new Match();
	testMatch.start();
	// Normal case
	ok( ! testMatch.isLastLevel(), "Test with a new Match object");
	// Limit case
	testMatch.level = missions.MISSIONS[testMatch.getMission()].levels.length;
	ok( testMatch.isLastLevel(), "Test in a limit case");
});

test("Match.isLastMission()", function(){
	testMatch = new Match();
	// Normal case
	var lastMission = (testMatch.mission === missions.MISSIONS.length);	//boolean value that is true only if the current mission is the last
	strictEqual( testMatch.isLastMission(), lastMission, "Test with default case");
	// Limit case
	testMatch.mission = missions.MISSIONS.length;;
	ok( testMatch.isLastMission(), "Test in a limit case");
});

test("Match.nextLevel()", function(){
	testMatch = new Match();
	testMatch.setMap(new Map(testMatch, 100, 100));
	testMatch.start();
	// Normal case
	var newLevel = testMatch.getLevel() + 1;	//Take the current level and increment it
	testMatch.nextLevel();
	strictEqual( testMatch.getLevel(), newLevel, "Test with default case");
	// Limit case, level = last level
	testMatch.level = missions.MISSIONS[testMatch.getMission()].levels.length;
	newLevel = testMatch.getLevel();
	testMatch.nextLevel();
	strictEqual( testMatch.getLevel(), newLevel, "Test with limit case");
});

test("Match.nextMission()", function(){
	testMatch = new Match();
	// Normal case
	var newMission = testMatch.getMission() + 1;//Take the current mission and increment it
	testMatch.nextMission();
	strictEqual(testMatch.getMission(), newMission, "Test #1 with default case");
	strictEqual(testMatch.getLevel(), 1, "Test #2 with default case");
	// Limit case, mission = missions.MISSIONS.length
	testMatch.mission = missions.MISSIONS.length;
	newMission = testMatch.getMission();
	testMatch.nextMission();
	strictEqual( testMatch.getMission(), newMission, "Test with limit case");
});
